#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h> // file option
#include <signal.h>
#include <dirent.h>
#include <pthread.h>
// #include <iostream>
// #include <sstream>
// #include <vector>
// #include <list>
// #include <map>
// #include <thread>
// #include <string>
// #include <iomanip>
// #include <fstream>
// #include <vector>
// #include <set>
// #include <algorithm>
// #include <unordered_map>
// #include <mutex>
// #include <atomic>
// #include <bits/wordsize.h>
// #include <bits/timesize.h>
//进程通讯有管道，命名管道，信号，消息队列，信号量，共享内存，sock。
//这里说命名管道，信号量。
//命名管道，多个接收只会有一个会接收到数据，单次接收最大64K。它就是单向的。
//信号，这里只列了收到kill信号。
//sock是双向的，但是速度较慢；共享内存快；消息队列最大包8K，单向。根据实际情况定哪一种。
int threadRunFlag = 1;
void signalUserCbkFunc(int s)
{
    if (s == SIGINT)
    {
        threadRunFlag = 0;
        printf("receive exit signal! quit now!\n");
    }
}

#define FIFO_CMD_FILE_NAME "/tmp/fifoCommTest.txt"

void *fifoThreadFunc(void *fval)
{
    // usleep(200 * 1000);
    mkfifo(FIFO_CMD_FILE_NAME, S_IFIFO | 0666);
    char tmpbuf[100 * 1024];
    int fifoCmdFd1 = open(FIFO_CMD_FILE_NAME, O_RDONLY);
    if (fifoCmdFd1 < 0)
    {
        printf("open fifo1 fail!\n");
        return NULL;
    }
    //文件描述符除了用select管理阻塞，也可以用O_NONBLOCK取消其阻塞。
    int flags = fcntl(fifoCmdFd1, F_GETFL);
    flags |= O_NONBLOCK;
    fcntl(fifoCmdFd1, F_SETFL, flags);
    printf("thread:\n");
    // write(fifoCmdFd1, "abc", 4);
    while (threadRunFlag)
    {
        memset(tmpbuf, 0, sizeof(tmpbuf));
        int tmplen = read(fifoCmdFd1, tmpbuf, sizeof(tmpbuf));
        if (tmplen > 0)
        {
            printf("fifo1 input len[%d]\n", tmplen);
            // printf("fifo1 input[%d]:%s\n", tmplen, tmpbuf);
        }
        usleep(10 * 1000);
    }
    return NULL;    
}

#define FIFO_MAX_LEN (200 * 1024)
int main()
{
    remove(FIFO_CMD_FILE_NAME);
    signal(SIGINT, signalUserCbkFunc);
    mkfifo(FIFO_CMD_FILE_NAME, S_IFIFO | 0666);
    char *tmpbuf = (char *)malloc(FIFO_MAX_LEN);
    fd_set rset;
    struct timeval tv;
    pthread_t tmpthread = -1;
    int maxSockfd = 0;
    int rc = 0;
    if(!tmpbuf)
    {
        printf("malloc err!\n");
        return -1;
    }
    int fifoCmdFd = open(FIFO_CMD_FILE_NAME, O_RDWR);
    if (fifoCmdFd < 0)
    {
        printf("open fifo fail!\n");
        goto freePoint;
    }
    pthread_create(&tmpthread, NULL, fifoThreadFunc, NULL);
    usleep(1000 * 1000);
    for(int i = 0; i < FIFO_MAX_LEN; i++)
    {
        tmpbuf[i] = '0' + i % 10;
    }
    tmpbuf[FIFO_MAX_LEN - 1] = 0;
    maxSockfd = write(fifoCmdFd, tmpbuf, FIFO_MAX_LEN);
    printf("main:%d\n", maxSockfd);
    while (threadRunFlag)
    {
        tv.tv_sec = 0;
        tv.tv_usec = 5 * 1000;
        FD_ZERO(&rset);
        if (fifoCmdFd >= 0)
        {
            FD_SET(fifoCmdFd, &rset);
            maxSockfd = fifoCmdFd + 1;
        }
        rc = select(maxSockfd, &rset, NULL, NULL, &tv);
        if (rc < 0)
        {
            printf("select err!\n");
            goto freePoint;
        }
        if (FD_ISSET(fifoCmdFd, &rset))
        {
            memset(tmpbuf, 0, FIFO_MAX_LEN);
            // int tmplen = read(fifoCmdFd, tmpbuf, sizeof(tmpbuf));
            // if (tmplen > 0)
            // {
            //     printf("fifo input len[%d]\n", tmplen);
            //     printf("fifo input[%d]:%s\n", tmplen, tmpbuf);
            // }
        }
    }
//goto很多地方说可以不用，确实。个人认为有他的独到之处。在需要统一释放资源，比如关闭文件，释放内存，解锁等，每个return都释放一次，还不如在统一地方来释放。
freePoint:
    if(tmpthread > 0)
    {
        pthread_join(tmpthread, NULL);
    }
    if(tmpbuf)
    {
        free(tmpbuf);
    }
    return 0;
}